import math
import wave
import io
# import pylab
import copy
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal 
from pydub import AudioSegment
from scipy.io import wavfile
from dtaidistance import dtw
from dtaidistance import dtw_visualisation as dtwvis

# 根据阈值找峰值
def findPeaks(times,data,threshold):
    t = []
    for i in range(len(data) - 1):
        if data[i] > data[i-1] and data[i] > data[i+1] and data[i] > threshold:
            t.append(i)
    fig = plt.figure(figsize=(25,5))
    plt.plot(times, data / np.max(data), linewidth = '1', color='green')
    plt.scatter(times[t],data[t] / np.max(data[t]),color='r')
    plt.plot(times[t],data[t] / np.max(data[t]))
    plt.grid()
    plt.xlabel(r'Time(s)',fontsize=25)
    plt.ylabel(r'Amplitude(relative)',fontsize=25)
    plt.tick_params(labelsize=20)
    fig.savefig('non-smooth.png',dpi=600,format='png',bbox_inches = 'tight')
    return t,data[t]

def findPeaks2(times,data,threshold):
    t = []
    for i in range(len(data) - 1):
        if data[i] > data[i-1] and data[i] > data[i+1] and data[i] > threshold:
            t.append(i)
    return t,data[t]

def findPeaks3(times,data,threshold):
    t = []
    for i in range(len(data) - 1):
        if data[i] > data[i-1] and data[i] > data[i+1] and data[i] > threshold:
            t.append(data[i])
        else:
            t.append(0)
    return t

# 找峰值，以某间距
def findPeaks_1(times,data,d):
    peaks = signal.find_peaks(data, distance=d)
    t = peaks[0]
    plt.figure(figsize=(25,5))
    plt.plot(times, data, linewidth = '1', color='green')
    plt.scatter(times[t],np.array(data)[t],color='r')
    plt.plot(times[t],np.array(data)[t])
    plt.grid()
    return t,np.array(data)[t]

# mp3转化为wav,并写入
def mp3Towav(mp3,path):
    MP3_File = AudioSegment.from_mp3(file=mp3)
    MP3_File.export(path, format="wav")

# 根据自相关滑动法求估计周期
def autocorr(x,y):
    result = []
    for i in range(len(x) - len(y) + 1):
        flag = 0
        for j in range(len(y)):
            flag = flag + y[j] * x[i + j]
        result.append(flag)
    return result

# 估计周期，默认返回为点数，如果点数
def estimateCycle(data,distance,mode="points",samplerate=0):
    peaks = signal.find_peaks(data,distance=distance)
    diff = getDiff(peaks[0])
    cycle = np.sum(np.array(diff)) // (len(diff))
    if mode == 'times':
        if samplerate == 0:
            print("请输入采样率,单位MHz")
            return
        return cycle / samplerate
    if mode == 'points':
        return cycle

# 得到差值序列
def getDiff(data):
    t_1 = []
    for i in range(len(data) - 1):
        t_1.append(data[i+1] - data[i])
    return t_1

# 加窗平滑曲线
def smooth(spec, win_len, window, beta = 20):
    """smooths a signal with kernel window of win_len number of inputs
    spec: Input data spectrum to be smoothed
    win_len: the size of the kernel window used to smooth the input
    window: type of kernel; e.g. 'blackman'
    """
    if window == 'kaiser':
        w = eval('np.'+window+'(win_len, beta)')
    elif window == 'flat':
        w = np.ones(len(win_len, 'd'))
    else:
        w = eval('np.'+window+'(win_len)')
    s = np.r_[spec[win_len-1 : 0 : -1], spec, spec[-1 : -win_len : -1]]
    y = np.convolve(w/w.sum(), s, mode='valid')
    return y[int(win_len / 2 - 1) : int(-win_len / 2)]

# 转化x轴为新的尺度
def getAxisX(data):
    diff = getDiff(data) #得到时间尺度上峰值位置的差值
    mind = min(diff)
    diffNew = np.array(diff) // mind # 以最小间距为单位1，形成新的时间序列
    t = np.zeros(len(diffNew)+1)
    for i in range(len(diffNew)):
        t[i+1] = t[i] + diffNew[i]
    t = np.array(t)
    t.astype(int)
    return t

# 转化为y轴为新的尺度
def getAxisY(data):
    data = np.round(data)
    p = 10
    for i in range(len(str(min(data))) - 3):
        p = p * 10
    data = np.round(np.array(data) / p)
    data = np.array(data)
    data.astype(int)
    data = data - np.min(data)
    return data

# 生成矩阵,padding为矩阵外围扩大的层数
def getMatrix(t,data,padding=0):
    t = getAxisX(t)
    data = getAxisY(data)

    m = np.zeros((int(np.max(data)+1+padding),int(t[-1]+1+padding)))
    for i in range(len(data)):
        m[int(np.max(data) - data[i]),int(t[i])] = 1
    return m
   
# 根据峰值生成方形轮廓
def getContour(data,diff):
    temp = []
    d = []
    for i in range(len(data)):
        if i == 0:
            temp.append(data[0])
        else:
            if abs(data[i] - data[i-1]) <= data[i-1] * diff:
                temp.append(data[i])
            else:
                d.extend(list(np.array(temp) / np.array(temp) * np.mean(temp)))
                temp = []
                temp.append(data[i])
    d.extend(list(np.array(temp) / np.array(temp) * np.mean(temp)))
    return d

def getContour1(data,diff):
    temp = []
    for i in range(len(data)):
        if i == 0:
            temp.append(data[0])
        else:
            if abs(data[i] - data[i-1]) <= data[i-1] * diff:
                temp.append(data[i-1])
            else:
                temp.append(data[i])
    return temp

# 计算两组数据的相似程度
def getSimilarity(t,s,path):
    # t:模板，被比较
    # 计算点权值，其中首尾的权值为0
    t = np.array(t)
    s = np.array(s)
    temp = copy.deepcopy(t) 
    score = 0
    temp[0],temp[-1] = 0,0
    w = temp / np.sum(temp)
    for i in range(len(path)-1):
        if (path[i+1][1] - path[i][1]) != 0 and (path[i+1][0] - path[i][0]) != 0:
            if ((t[path[i+1][0]] - t[path[i][0]]) * (s[path[i+1][1]] - s[path[i][1]])) >= 0:
                score = score + 0.5 * (w[path[i+1][0]] + w[path[i][0]])
            else:
                score = score - 0.5 * (w[path[i+1][0]] + w[path[i][0]])
    return score

def getSimilarity1(t,s,path):
    # t:模板，被比较
    # 计算点权值，其中首尾的权值为0
    t = np.array(t)
    s = np.array(s)
    temp = copy.deepcopy(t) 
    score = 0
    temp[0],temp[-1] = 0,0
    w = temp / np.sum(temp)
    sum = []
    temp1 = -1
    temp2 = -1
    firstTemp1 = False
    firstTemp2 = False
    for i in range(len(path)-1):
        if (path[i+1][1] - path[i][1]) != 0 and (path[i+1][0] - path[i][0]) != 0:
            if ((t[path[i+1][0]] - t[path[i][0]]) * (s[path[i+1][1]] - s[path[i][1]])) >= 0:
                score = score + 0.5 * (w[path[i+1][0]] + w[path[i][0]])
            else:
                score = score - 0.5 * (w[path[i+1][0]] + w[path[i][0]])
        elif((path[i+1][1] - path[i][1]) == 0):
            if(temp1 == path[i+1][1]):
                sum.append(w[path[i][0]])
            else:
                if(not firstTemp1):
                    firstTemp1 = True
                    temp1 = path[i+1][1]
                else:
                    temp1 = path[i+1][1]
                    sum.append(w[path[i][0]])
                    score = score - np.sum(sum) / len(sum)
                    sum = []
        elif((path[i+1][0] - path[i][0]) == 0):
            if(temp2 != path[i+1][0]):
                if(not firstTemp2):
                    firstTemp2 = True
                    temp2 = path[i+1][0]
                else:
                    score = score - w[path[i][0]]
                    temp2 = path[i+1][0]
    return score